package com.coocaa.typhoon.api.config.elasticsearch;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolException;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultRedirectStrategy;
import org.apache.http.protocol.HttpContext;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;

/**
 * @author bijiahao
 * @date : 2025/10/21 15:39
 * @description
 */
@Slf4j
@Configuration
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
    @Autowired
    private ElasticsearchProperties elasticsearchProperties;

    @Override
    @Bean
    public RestHighLevelClient elasticsearchClient() {
        log.info("开始初始化Elasticsearch客户端（无认证模式）...");
        log.info("配置节点: {}", elasticsearchProperties.getNodesInfo());

        // 获取配置的节点
        HttpHost[] httpHosts = elasticsearchProperties.getHttpHosts();

        // 构建RestClientBuilder
        RestClientBuilder builder = RestClient.builder(httpHosts);

        // 配置连接超时和请求配置
        configureRequestConfig(builder);

        // 配置HTTP客户端
        configureHttpClient(builder);

        // 构建客户端
        RestHighLevelClient client = new RestHighLevelClient(builder);

        log.info("Elasticsearch客户端初始化完成，节点数量: {}", httpHosts.length);
        return client;
    }

    /**
     * 配置请求参数
     */
    private void configureRequestConfig(RestClientBuilder builder) {
        builder.setRequestConfigCallback(requestConfigBuilder -> {
            requestConfigBuilder.setConnectTimeout(elasticsearchProperties.getConnectionTimeoutMillis());
            requestConfigBuilder.setSocketTimeout(elasticsearchProperties.getSocketTimeoutMillis());
            // 设置连接请求超时
            requestConfigBuilder.setConnectionRequestTimeout(elasticsearchProperties.getRequestTimeoutMillis());
            return requestConfigBuilder;
        });
    }

    /**
     * 配置HTTP客户端
     */
    private void configureHttpClient(RestClientBuilder builder) {
        builder.setHttpClientConfigCallback(httpClientBuilder -> {
            // 配置连接池
            httpClientBuilder.setMaxConnTotal(elasticsearchProperties.getPool().getMaxTotal());
            httpClientBuilder.setMaxConnPerRoute(elasticsearchProperties.getPool().getDefaultMaxPerRoute());

            // 配置连接存活时间
            httpClientBuilder.setKeepAliveStrategy((response, context) -> 60000); // 60秒

            // 配置重定向策略
            httpClientBuilder.setRedirectStrategy(new CustomRedirectStrategy(
                    elasticsearchProperties.getRetry().getMaxRetries()
            ));

            log.info("Elasticsearch客户端配置完成（无认证）");
            return httpClientBuilder;
        });
    }

    /**
     * 自定义重定向策略
     */
    private static class CustomRedirectStrategy extends DefaultRedirectStrategy {
        private final int maxRedirects;

        public CustomRedirectStrategy(int maxRedirects) {
            this.maxRedirects = maxRedirects;
        }

        @Override
        public boolean isRedirected(HttpRequest request,
                                    HttpResponse response,
                                    HttpContext context) throws ProtocolException {

            int statusCode = response.getStatusLine().getStatusCode();
            boolean isRedirect = super.isRedirected(request, response, context);

            if (isRedirect) {
                log.debug("检测到HTTP重定向请求，状态码: {}", statusCode);
            }

            return isRedirect;
        }

        @Override
        public HttpUriRequest getRedirect(HttpRequest request,
                                          HttpResponse response,
                                          HttpContext context) throws ProtocolException {

            // 获取当前重定向次数
            Integer redirectCount = (Integer) context.getAttribute("http.redirect-count");
            if (redirectCount == null) {
                redirectCount = 0;
            }

            // 检查是否超过最大重定向次数
            if (redirectCount >= maxRedirects) {
                log.warn("已达到最大重定向次数: {}", maxRedirects);
                throw new RuntimeException("超过最大重定向次数限制: " + maxRedirects);
            }

            // 增加重定向计数
            redirectCount++;
            context.setAttribute("http.redirect-count", redirectCount);

            log.debug("执行第{}次重定向，最大限制: {}", redirectCount, maxRedirects);

            // 使用默认的重定向逻辑
            return super.getRedirect(request, response, context);
        }
    }

    /**
     * 创建ElasticsearchRestTemplate
     */
    @Bean
    public ElasticsearchRestTemplate elasticsearchRestTemplate() {
        return new ElasticsearchRestTemplate(elasticsearchClient());
    }

    /**
     * 创建ElasticsearchConverter
     */
    @Bean
    public ElasticsearchConverter elasticsearchConverter() {
        return new MappingElasticsearchConverter(elasticsearchMappingContext());
    }

    /**
     * 创建ElasticsearchMappingContext
     */
    @Bean
    @Override
    public SimpleElasticsearchMappingContext elasticsearchMappingContext() {
        return new SimpleElasticsearchMappingContext();
    }

    /**
     * 创建低级RestClient
     */
    @Bean
    public RestClient restClient() {
        return elasticsearchClient().getLowLevelClient();
    }
}
